package com.prime;

import java.util.Map;
import java.util.concurrent.*;

public class RightPrimeChecker implements CanCheckIfPrime {

    private static final WrongIfPrimeChecker delegate = new WrongIfPrimeChecker();

    private static Map<Integer, Future<Boolean>> isPrimeCache = new ConcurrentHashMap<>();

    /**
     * Thread safe!
     */
    @Override
    public final boolean isPrime(int number) {

        Future<Boolean> future = isPrimeCache.get(number);

        if (future == null) {
            Callable<Boolean> eval = new Callable<Boolean>() {
                @Override
                public Boolean call() throws Exception {
                    return delegate.isPrime(number);
                }
            };
            FutureTask<Boolean> futureTask = new FutureTask<>(eval);
            if ((future = isPrimeCache.putIfAbsent(number, futureTask)) == null) {
                future = futureTask;
                futureTask.run();
            }
        }
        try {
            return future.get();
        } catch (CancellationException | InterruptedException | ExecutionException e) {
            isPrimeCache.remove(number, future);
            e.printStackTrace();
        }
        return false;
    }

    public static int getCountOfPrimeNumbers(int max, int threadsNumber) throws ExecutionException, InterruptedException {

        ExecutorService executor = Executors.newFixedThreadPool(threadsNumber);
        Integer counter = 0;
        for (int i = 0; i < threadsNumber; i++) {
            Runnable worker = () -> {
                RightPrimeChecker checker = new RightPrimeChecker();
                for (int j = max; j >= 2; j--) {
                    checker.isPrime(j);
                }
            };
            executor.execute(worker);
        }

        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);// just for test

        for (Map.Entry<Integer, Future<Boolean>> entry : isPrimeCache.entrySet()) {
            if (entry.getValue().get()) {
                counter++;
            }
        }
        return counter;
    }

}
